package com.sylli.oeuf.server;

import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.api.IConnection;
import org.red5.server.api.IScope;
import org.red5.server.api.stream.IServerStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sylli.oeuf.server.db.DatabaseProviderBundle;
import com.sylli.oeuf.server.exception.BasedException;
import com.sylli.oeuf.server.manager.SessionManager;
import com.sylli.oeuf.server.object.transferable.CharacterGeneralInfoTO;
import com.sylli.oeuf.server.util.GeneratorUtil;
import com.sylli.oeuf.server.util.StringUtil;

public class Application extends ApplicationAdapter {

	protected static Logger log = LoggerFactory.getLogger( "core.Application" );
	
	private static IServerStream serverStream;
	
	private IScope appScope;
	
	private DatabaseProviderBundle providers = DatabaseProviderBundle.getInstance();

	private SessionManager sessionManager;
	
	private boolean properStarted = false;
	
	@Override
	public boolean appStart(IScope scope)
	{
		log.info("Application.start() " + GeneratorUtil.getCoreStreamPath().getAbsolutePath());
		appScope = scope;
		
		// must be initialized after SystemManager initialized.
		sessionManager = SessionManager.getInstance();
		
		properStarted = true;
		
		log.info("Application.start() completed, properStartFlag={}", properStarted);
		return true;
	}
	
	@Override
    public boolean appConnect( IConnection conn , Object[] params )
    {
		if (!properStarted) {
			log.error("Attempt to connect the server from " + conn.getClient().getId() + " while system is unstable; reason={properInitialized="+ properStarted + "} - check serverConfig.xml");
			return rejectClient("System does not initialized properly.");
		}
		
		/* client connect - then create the authKey object. */
		if (params.length < 1)
		{
			log.error("Attempt to connect the server from " + conn.getClient().getId() + " while system is unstable; reason={client does not supply the clientId value} - check client version");
			return rejectClient("Client id is not supplied.");
		}
		
    	log.info( "Connected [" + conn.getClient().getId() + "]");
    	
    	if (log.isDebugEnabled()) {
	    	log.debug("Connection parameters = ...");
	    	StringUtil.printArray(log, params);
	    	
	    	log.debug("Connection attributes = ...");
	    	StringUtil.printArray(log, conn.getAttributes());
    	}
    	
    	String characterName = "";
    	if (params[0] instanceof String) {
    		characterName = (String) params[0];
    	} else {
    		log.error("Type marshaling Fail; characterName type is " + params[0].getClass().getName());
    		return rejectClient("clientId type is neither Integer nor Long.");
    	}
    	log.info( "Verify [clientId = " + characterName + "]");
    	
    	try {
    		CharacterGeneralInfoTO o = sessionManager.getCharacterInfoFromCharacterName(characterName);
    		if (o == null) {
    			return rejectClient("character name is invalid.");
    		} else {
    			// associate the characterId with the clientId
    			sessionManager.bind(o.getCharId());
    		}
		} catch (BasedException e) {
			log.error("Verification Fail" + e);
    		return rejectClient("Unable to verify the given character name.");
		}
    	
    	// TODO: Try verify connection
		log.info( "Verification successful!");
    	return true;
    }
	
    @Override
    public void appDisconnect( IConnection conn )
    {
    	sessionManager.unbind();
    	log.info( "Disconnected [" + conn.getClient().getId() + "]");
    	super.appDisconnect( conn );
    }

    @Override
    public void appStop( IScope app )
    {
    	// kill live streams
    	log.info( "Application Stopped" );
    	if (appScope == app && serverStream != null) {
			serverStream.close();
		}
    	super.appStop(app);
    }
    
}
